package dotsandboxs;

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.util.Arrays;

import javax.swing.JOptionPane;

/**
 * Monitor.java 继承了MouseAdapter适配器，作为界面的鼠标事件监听器
 */
public class Monitor extends MouseAdapter {
    /**
     *格子自由度为4
     */
    final int DOFISFULL = 4;
    /**
     * 游戏还没开始
     */
    final int NOTSTART = 0;
    /**
     * 人-人 模式
     */
    final int MAN_MAN_MODE = 1;
    /**
     * 人-电脑 模式
     */
    final int MAN_MACHINE_MODE = 2;
    /**
     * 电脑-电脑 模式
     */
    final int MACHINE_MACHINE_MODE = 3;

    ChessGUI gui;
    int[] temp = new int[2];// 临时用于存储点的数组

    /**
     * 监听器类带参数构造方法
     *
     * @param gui 界面类对象
     */
    public Monitor(ChessGUI gui) {
        this.gui = gui;
    }


    /**
     * 实现了mousePressed方法
     *
     * @param e 鼠标事件对象
     */
    public void mousePressed(MouseEvent e) {
        if (NOTSTART == ChessGUI.gameMode) {
            JOptionPane.showMessageDialog(gui.frame, "请先开始游戏", "开始", JOptionPane.ERROR_MESSAGE);
            return;
        }
        if (MAN_MAN_MODE == ChessGUI.gameMode) {
            // 人vs人模式
            temp[ChessGUI.count] = getDot(e.getX(), e.getY());
            ChessGUI.count++;
            if (ChessGUI.count % 2 == 0) {
                // 判断是否合法，一切操作都基于行棋合法
                if (legalJudge(temp[0], temp[1])) {
                    // 进行大小交换，确保第一个数比第二个小
                    if (temp[0] > temp[1]) {
                        int t = temp[0];
                        temp[0] = temp[1];
                        temp[1] = t;
                    }
                    int tSide = getSide(temp[0], temp[1]);
                    // 余数为0表示当前是红方行棋,否则就是蓝方行棋
                    if (ChessGUI.color % 2 == 0) {
                        // 判断是否数组里面已经有这条边了，如果有这则直接return
                        for (int redSideIndex = 0; redSideIndex < ChessGUI.redSide.length; redSideIndex++) {
                            if (tSide == ChessGUI.side[redSideIndex]) {
                                JOptionPane.showMessageDialog(gui.frame, "该边已经被占领，请选择另外一条边！", "重复",
                                        JOptionPane.INFORMATION_MESSAGE);
                                ChessGUI.count = 0;// 标志置0
                                return;
                            }
                        }
                        gui.g.setColor(Color.red);
                        drawLine(temp[0], temp[1]);// 以这两点划线
                        // 存储边
                        ChessGUI.side[ChessGUI.sideCount] = tSide;
                        ChessGUI.redSide[ChessGUI.redSideCount] = tSide;
                        ChessGUI.sideCount++;
                        ChessGUI.redSideCount++;
                        changeDOF(tSide); // 改变格子自由度
                        ChessGUI.color++;// 颜色计数器加1
                        gui.frame.repaint();// 重绘棋盘
                        Status status = new Status(gui);// 实例化一个状态对象
                        ChessGUI.list.add(status);// 将当前棋盘存入列表
                   } else {
                       // 判断是否数组里面已经有这条边了，如果有这则直接return
                       for (int blueSideIndex = 0; blueSideIndex < ChessGUI.blueSide.length; blueSideIndex++) {
                           if (tSide == ChessGUI.side[blueSideIndex]) {
                               JOptionPane.showMessageDialog(gui.frame, "该边已经被占领，请选择另外一条边！", "重复",
                                       JOptionPane.INFORMATION_MESSAGE);
                               ChessGUI.count = 0;// 标志置0
                                temp = new int[2];// 临时数组置0
                                return;
                            }
                        }
                        gui.g.setColor(Color.blue);
                        drawLine(temp[0], temp[1]);// 以这两点划线
                        // 存储边
                        ChessGUI.side[ChessGUI.sideCount] = tSide;
                        ChessGUI.blueSide[ChessGUI.blueSideCount] = tSide;
                        ChessGUI.sideCount++;
                        ChessGUI.blueSideCount++;
                        changeDOF(tSide); // 改变格子自由度
                        ChessGUI.color++;// 颜色计数器加1
                        gui.frame.repaint();// 重绘棋盘
                        Status status = new Status(gui);// 实例化一个状态对象
                        ChessGUI.list.add(status);// 将当前棋盘存入列表
                    }
                    winLoseJudge();// 执行完代码之后调用判断输赢函数
                    ChessGUI.count = 0;
                    temp = new int[2];// 临时数组置0
                } else {
                    JOptionPane.showMessageDialog(gui.frame, "行棋不合法", "合法性", JOptionPane.ERROR_MESSAGE);
                    ChessGUI.count = 0;// 重新置为0，重新进入循环
                    temp = new int[2];// 临时数组置0
                }
            }
        }
        if (MAN_MACHINE_MODE == ChessGUI.gameMode) {
            // 人vs电脑模式
            temp[ChessGUI.count] = getDot(e.getX(), e.getY());
            ChessGUI.count++;
            if (ChessGUI.count % 2 == 0) {
                // 判断是否合法，一切操作都基于行棋合法
                if (legalJudge(temp[0], temp[1])) {
                    // 进行大小交换，确保第一个数比第二个小
                    if (temp[0] > temp[1]) {
                        int t = temp[0];
                        temp[0] = temp[1];
                        temp[1] = t;
                    }
                    int tSide = getSide(temp[0], temp[1]);
                    // 余数为0表示当前是红方行棋,否则就是蓝方行棋
                    if (ChessGUI.color % 2 == 0) {
                        // 判断是否数组里面已经有这条边了，如果有这则直接return
                        for (int redSideIndex = 0; redSideIndex < ChessGUI.redSide.length; redSideIndex++) {
                            if (tSide == ChessGUI.side[redSideIndex]) {
                                JOptionPane.showMessageDialog(gui.frame, "该边已经被占领，请选择另外一条边！", "重复",
                                        JOptionPane.INFORMATION_MESSAGE);
                                ChessGUI.count = 0;// 标志置0
                                return;
                            }
                        }
                        gui.g.setColor(Color.red);
                        drawLine(temp[0], temp[1]);// 以这两点划线
                        // 存储边
                        ChessGUI.side[ChessGUI.sideCount] = tSide;
                        ChessGUI.redSide[ChessGUI.redSideCount] = tSide;
                        ChessGUI.sideCount++;
                        ChessGUI.redSideCount++;
                        changeDOF(tSide); // 改变格子自由度
                        ChessGUI.color++;// 颜色计数器加1
                        gui.frame.repaint();// 重绘棋盘
                        if (ChessGUI.color % 2 == 1) {
                            while (ChessGUI.color % 2 == 1 && ChessGUI.gameMode != 0) {
                                new AI(gui);
                            }
                        }
                        ChessGUI.list.add(new Status(gui));// 将当前棋盘存入列表
                    } else {
                        // 判断是否数组里面已经有这条边了，如果有这则直接return
                        for (int blueSideIndex = 0; blueSideIndex < ChessGUI.blueSide.length; blueSideIndex++) {
                            if (tSide == ChessGUI.side[blueSideIndex]) {
                                JOptionPane.showMessageDialog(gui.frame, "该边已经被占领，请选择另外一条边！", "重复",
                                        JOptionPane.INFORMATION_MESSAGE);
                                ChessGUI.count = 0;// 标志置0
                                temp = new int[2];// 临时数组置0
                                return;
                            }
                        }
                        gui.g.setColor(Color.blue);
                        drawLine(temp[0], temp[1]);// 以这两点划线
                        // 存储边
                        ChessGUI.side[ChessGUI.sideCount] = tSide;
                        ChessGUI.blueSide[ChessGUI.blueSideCount] = tSide;
                        ChessGUI.sideCount++;
                        ChessGUI.blueSideCount++;
                        changeDOF(tSide); // 改变格子自由度
                        ChessGUI.color++;// 颜色计数器加1
                        gui.frame.repaint();// 重绘棋盘

                        if (ChessGUI.color % 2 == 0) {
                            while (ChessGUI.color % 2 == 0 && ChessGUI.gameMode != 0) {
                                new AI(gui);
                            }
                        }
                        ChessGUI.list.add(new Status(gui));// 将当前棋盘存入列表
                    }
                    System.out.println("红方占据的格子数：" + ChessGUI.redBoxCount);
                    System.out.println(Arrays.toString(ChessGUI.redBox));
                    System.out.println("蓝方占据的格子数：" + ChessGUI.blueBoxCount);
                    System.out.println(Arrays.toString(ChessGUI.blueBox));
                    System.out.println();
                    winLoseJudge();// 执行完代码之后调用判断输赢函数
                    ChessGUI.count = 0;
                    temp = new int[2];// 临时数组置0
                } else {
                    JOptionPane.showMessageDialog(gui.frame, "行棋不合法", "合法性", JOptionPane.ERROR_MESSAGE);
                    ChessGUI.count = 0;// 重新置为0，重新进入循环
                    temp = new int[2];// 临时数组置0
                }
            }
        }
        if (MACHINE_MACHINE_MODE == ChessGUI.gameMode) {
            // 电脑vs电脑模式
            new AI(gui);
            try {
                Thread.sleep(150);
            } catch (InterruptedException e1) {
                e1.printStackTrace();
            }
            System.out.println("红方占据的格子数：" + ChessGUI.redBoxCount);
            System.out.println(Arrays.toString(ChessGUI.redBox));
            System.out.println("蓝方占据的格子数：" + ChessGUI.blueBoxCount);
            System.out.println(Arrays.toString(ChessGUI.blueBox));
            System.out.println();
        }
    }

    /**
     * 将点击棋盘获得的坐标转换为一个2位数
     *
     * @param x 鼠标点击位置的x坐标（像素级）
     * @param y 鼠标点击位置的y坐标（像素级）
     * @return x*10+y
     */
    int getDot(int x, int y) {
        int realX = x - ChessGUI.INITWIDTH;
        int realY = y - ChessGUI.INITHEIGHT;
        for (int row = 0; row <= 5; row++) {
            for (int col = 0; col <= 5; col++) {
                // 误差标准 误差允许范围为20*20的正方形
                int d = (row * 100 - realX) * (row * 100 - realX) + (col * 100 - realY) * (col * 100 - realY);
                if (d <= 400)
                    return row * 10 + col;
            }
        }
        return -1;
    }

    /**
     * 两个用二位数表示的点转成四位数表示一条边
     *
     * @param x 已经使用获得点函数转化之后的二位数点（第一个点）
     * @param y 已经使用获得点函数转化之后的二位数点（第二个点）
     * @return x * 100 + y
     */
    int getSide(int x, int y) {
        return x * 100 + y;
    }

    /**
     * 行棋合法性判断
     *
     * @param dotFirst 已经使用获得点函数转化之后的二位数点（第一个点）
     * @param dotLast  已经使用获得点函数转化之后的二位数点（第二个点）
     */
    boolean legalJudge(int dotFirst, int dotLast) {
        int xf = dotFirst / 10;
        int yf = dotFirst % 10;
        int xl = dotLast / 10;
        int yl = dotLast % 10;
        if (xf < 0 || yf < 0 || xl < 0 || yl < 0) {
            return false;
        }
        if ((xf - xl) == 0 && ((yf - yl) == -1 || (yf - yl) == 1))
            return true;
        else if (((xf - xl) == -1 || (xf - xl) == 1) && (yf - yl) == 0)
            return true;
        else
            return false;
    }

    /**
     * 两点连线函数
     *
     * @param dotFirst 已经使用获得点函数转化之后的二位数点（第一个点）
     * @param dotLast  已经使用获得点函数转化之后的二位数点（第二个点）
     */
    void drawLine(int dotFirst, int dotLast) {
        int xf = dotFirst / 10;
        int yf = dotFirst % 10;
        int xl = dotLast / 10;
        int yl = dotLast % 10;
        Graphics2D g2d = (Graphics2D) gui.g;
        g2d.setStroke(new BasicStroke(5.5f));
        gui.g.drawLine(xf * 100 + ChessGUI.INITWIDTH, yf * 100 + ChessGUI.INITHEIGHT,
                xl * 100 + ChessGUI.INITWIDTH, yl * 100 + ChessGUI.INITHEIGHT);
    }


    /**
     * 格子自由度的变化函数
     *
     * @param side 用转换边函数得到的一个四位数
     */
    void changeDOF(int side) {
        // 拆分成坐标
        int dotFirst = side / 100;
        int dotLast = side % 100;
        int xf = dotFirst / 10;
        int yf = dotFirst % 10;
        int xl = dotLast / 10;
        int yl = dotLast % 10;
        // 建立点和格子的联系
        // 是边界，else就不是边界的
        if (xl == xf && xf == 0 || xl == xf && xf == 5 || yl == yf && yf == 0 || yl == yf && yf == 5) {
            if (xl == xf) {
                int index = 5 * yl + xl * xl - 21 * xl / 5 - 5;
                ChessGUI.block[index]++;
                if (addBox(ChessGUI.block, index)) {
                    ChessGUI.color++;// 因为占领一个格子之后要再下一条边
                }
            } // 纵向
            if (yl == yf) {
                ChessGUI.block[4 * yl + xl - 1]++;
                if (addBox(ChessGUI.block, 4 * yl + xl - 1)) {
                    ChessGUI.color++;// 因为占领一个格子之后要再下一条边
                }
            } // 横向
        } else {
            if (xl == xf) {
                ChessGUI.block[5 * yl + xl - 6]++;// 左边
                boolean  isLDOFFull = addBox(ChessGUI.block, 5 * yl + xl - 6);
                ChessGUI.block[5 * yl + xl - 5]++;// 右边
                boolean isRDOFFull = addBox(ChessGUI.block, 5 * yl + xl - 5);
                if (isLDOFFull || isRDOFFull) {
                    ChessGUI.color++;// 因为占领一个格子之后要再下一条边
                }
            } // 纵向
            if (yl == yf) {
                ChessGUI.block[5 * yl + xl - 6]++;// 上面
                boolean isUDOFFull = addBox(ChessGUI.block, 5 * yl + xl - 6);
                ChessGUI.block[5 * yl + xl - 1]++;// 下面
                boolean ifDDOFFull = addBox(ChessGUI.block, 5 * yl + xl - 1);
                if (isUDOFFull || ifDDOFFull) {
                    ChessGUI.color++;// 因为占领一个格子之后要再下一条边
                }
            } // 横向
        }
    }

    /**
     * 存储格子进入数组函数
     *
     * @param block 格子数组
     * @param index 格子的下标
     */
     boolean addBox(int[] block, int index) {
        if (DOFISFULL == block[index]) {
            // 判断行棋方
            if (0 == ChessGUI.color % 2) {
                // 判断下标是否为0，如果是则赋值为-1，否则就赋值为原来的下标
                if (index == 0) {
                    ChessGUI.redBox[ChessGUI.redBoxCount] = index - 1;
                } else {
                    ChessGUI.redBox[ChessGUI.redBoxCount] = index;
                }
                ChessGUI.redBoxCount++;
                ChessGUI.redBlock++;

            } else {
                // 判断下标是否为0，如果是则赋值为-1，否则就赋值为原来的下标
                if (0 == index) {
                    ChessGUI.blueBox[ChessGUI.blueBoxCount] = index - 1;
                } else {
                    ChessGUI.blueBox[ChessGUI.blueBoxCount] = index;
                }
                ChessGUI.blueBoxCount++;
                ChessGUI.blueBlock++;
            }
            return true;

        } else {
            return false;
        }

    }

    /**
     * 输赢判断函数
     */
    void winLoseJudge() {
        if (ChessGUI.redBlock + ChessGUI.blueBlock == 25) {
            if (ChessGUI.redBlock > ChessGUI.blueBlock) {
                JOptionPane.showMessageDialog(gui.frame, "红方胜利！请重新开始游戏", "胜利", JOptionPane.INFORMATION_MESSAGE);
            } else {
                JOptionPane.showMessageDialog(gui.frame, "蓝方胜利！请重新开始游戏", "胜利", JOptionPane.INFORMATION_MESSAGE);
            }
            ChessGUI.gameMode = 0;// 标志游戏结束
        }

    }

}
